package main

import "fmt"

/*
23_访问者模式
概念：表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
*/

type Customer interface {
	Accept(visitor Visitor)
}

type Visitor interface {
	Visit(customer Customer)
}

// 客户群
type CustomerCol struct {
	customers []Customer
}

func (c *CustomerCol) Add(customer Customer) {
	c.customers = append(c.customers, customer)
}

func (c *CustomerCol) Accept(visitor Visitor) {
	for _, customer := range c.customers {
		customer.Accept(visitor)
	}
}

// 企业级客户
type EnterpriseCustomer struct {
	name string
}

func NewEnterpriseCustomer(name string) *EnterpriseCustomer {
	return &EnterpriseCustomer{name: name}
}

func (e *EnterpriseCustomer) Accept(visitor Visitor) {
	visitor.Visit(e)
}

type IndividualCustomer struct {
	name string
}

func NewIndividualCustomer(name string) *IndividualCustomer {
	return &IndividualCustomer{name: name}
}

func (i *IndividualCustomer) Accept(visitor Visitor) {
	visitor.Visit(i)
}

// 访问器
type ServiceRequestVisitor struct {
}

func (s *ServiceRequestVisitor) Visit(customer Customer) {
	switch c := customer.(type) {
	case *EnterpriseCustomer:
		fmt.Printf("服务企业级客户：%s\n", c.name)
	case *IndividualCustomer:
		fmt.Printf("服务个人客户:%s\n", c.name)
	}
}

type AnalysisVisitor struct {
}

func (a *AnalysisVisitor) Visit(customer Customer) {
	switch c := customer.(type) {
	case *EnterpriseCustomer:
		fmt.Printf("分析企业级客户:%s\n", c.name)
	}
}

func main() {
	c := &CustomerCol{}
	c.Add(NewEnterpriseCustomer("格力"))
	c.Add(NewEnterpriseCustomer("美的"))
	c.Add(NewIndividualCustomer("山寨"))
	c.Accept(&ServiceRequestVisitor{})
	fmt.Println("==============")
	c.Add(NewEnterpriseCustomer("格力"))
	c.Add(NewIndividualCustomer("山寨"))
	c.Add(NewEnterpriseCustomer("美的"))
	c.Accept(&AnalysisVisitor{})
}
